/*
 * Copyright (C) 2010 Fred Barrie This program is free software: you can
 * redistribute it and/or modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version. This program is distributed
 * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details. You should have received
 * a copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
package org.aergia.vinny.main;

import java.io.File;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collection;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.aergia.vinny.core.ApiResult;
import org.aergia.vinny.core.enums.DayOfWeek;
import org.aergia.vinny.database.Database;
import org.aergia.vinny.database.DatabaseImpl;
import org.aergia.vinny.database.pojo.Location;
import org.aergia.vinny.database.pojo.OperatingHours;
import org.aergia.vinny.database.pojo.Organization;
import org.aergia.vinny.database.pojo.VinnyOption;
import org.aergia.vinny.database.pojo.VinnyUser;
import org.aergia.vinny.database.pojo.Workstation;
import org.aergia.vinny.database.util.BackupUtil;
import org.aergia.vinny.engine.Engine;
import org.aergia.vinny.engine.EngineImpl;
import org.aergia.vinny.engine.VinnyConfiguration;
import org.aergia.vinny.gui.controller.VinnyController;
import org.aergia.vinny.gui.controller.VinnyControllerImpl;
import org.aergia.vinny.gui.util.DialogUtil;
import org.aergia.vinny.gui.view.InitializeLocation;
import org.aergia.vinny.gui.view.UserFrame;
import org.aergia.vinny.util.DateUtil;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
 * @author Fred
 */
public class UserMain {

	private static String PRODUCT_NAME = "trackin' it!";

	/**
	 * @param args
	 */
	public static void main(final String[] args) throws Exception {
		UIManager.setLookAndFeel(VinnyMain.PREFERRED_LOOK_AND_FEEL);

		final UserMain main = new UserMain();
		main.initialize();
	}

	private final VinnyController controller;
	private final Engine engine;
	private UserFrame frame;

	public UserMain() {
		final EntityManagerFactory emf = Persistence.createEntityManagerFactory("vinny");
		final EntityManager em = emf.createEntityManager();
		final Database database = new DatabaseImpl(em);

		try {
			BackupUtil.backupDatabase(database);
		} catch (final Exception e) {
			e.printStackTrace();
		}

		this.engine = new EngineImpl(database);
		this.controller = new VinnyControllerImpl(this.engine);
	}

	public void initialize() {

		final VinnyConfiguration cfg = new VinnyConfiguration();
		cfg.loadConfigurationFile(System.getProperty("user.home") + "/vinny/conf/cfg.xml");
		int locationId = cfg.getLocationId("vinny");

		if ((locationId == 0) && !this.engine.isDatabaseInitialized()) {
			locationId = this.initializeLocation();
		}

		this.engine.getOption(VinnyOption.PRODUCT_NAME, UserMain.PRODUCT_NAME);
		final ApiResult<Location> locResult = this.engine.getLocation(locationId);
		if (!locResult.isError()) {
			locResult.getResult().getName();
		} else {
			DialogUtil.alert(null, "Invalid location.", "Configuration error.");
			System.exit(-1);
		}

		this.engine.setLocation(locResult.getResult());

		if (cfg.getWorkstationId("vinny") == 0) {
			String hostName = Long.toString(System.currentTimeMillis());
			try {
				hostName = InetAddress.getLocalHost().getHostName();
			} catch (final Exception e) {
				// ignore
			}
			final ApiResult<Workstation> workstationResult = this.engine.installWorkstation("workstation-" + hostName);
			if (!workstationResult.isError()) {
				cfg.setWorkstationId("vinny", workstationResult.getResult().getId());
				cfg.saveConfigurationFile(System.getProperty("user.home") + "/vinny/conf/cfg.xml");
			}
		}

		final ApiResult<Workstation> apiResult = this.engine.getWorkstation(cfg.getWorkstationId("vinny"));
		this.engine.setWorkstation(apiResult.getResult());

		final ApiResult<VinnyUser> userResult = this.controller.validateUser("admin", "password");

		this.frame = new UserFrame(this.controller, userResult.getResult());
		this.frame.setVisible(true);
		this.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}

	private int initializeLocation() {
		final InitializeLocation dialog = new InitializeLocation();
		dialog.setVisible(true);
		final String orgName = dialog.getOrganizationName();
		final Organization org = new Organization(orgName);
		final String locName = dialog.getLocationName();
		final Location location = new Location(locName, org);
		final int rate = dialog.getRate();
		final Collection<OperatingHours> operatingHours = new ArrayList<OperatingHours>();
		for (final DayOfWeek day : DayOfWeek.values()) {
			if (dialog.isDayDefined(day)) {
				final int startTime = dialog.getStartTime(day);
				final int endTime = dialog.getEndTime(day);
				operatingHours.add(new OperatingHours(day, startTime, endTime));
			}
		}
		final ApiResult<Location> locResult = this.engine.installLocation(org, location, operatingHours, rate, DateUtil.getInstance());
		if (!locResult.isError()) {
			this.saveConfigurationFile(locResult.getResult().getId());
			return locResult.getResult().getId();
		}
		return 0;
	}

	private void saveConfigurationFile(final int locationId) {
		try {
			final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
			final Document document = builder.newDocument();
			final Element root = document.createElement("configuration");
			final Element location = document.createElement("location");
			final Attr id = document.createAttribute("id");
			id.setNodeValue(Integer.toString(locationId));
			location.setAttribute("id", Integer.toString(locationId));
			root.appendChild(location);
			document.appendChild(root);

			final Transformer transformer = TransformerFactory.newInstance().newTransformer();
			final DOMSource source = new DOMSource(document);
			final StreamResult result = new StreamResult(new File("vinny.xml"));
			transformer.transform(source, result);

		} catch (final Exception e) {
			e.printStackTrace();
		}
	}
}
